#include <pthread.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h> 
#include "event.h"
#include "uart.h"
#include "js/common/platform.h"

static int fd;

static struct _event uart_event;

static struct uart_state _uart;

void *uart(void *arg)
{
    struct fd_set fds; 
    int len;

    while(1){
        FD_ZERO(&fds); 
        FD_SET(fd,&fds); 
        int n = select(fd+1,&fds,&fds,NULL,NULL);
        if(n < 0){
            perror("select");
        } else {
            ioctl(fd,FIONREAD,&len);
            if(len && _uart.stats.rx_stats != rx_done){
                uint8_t *data = _uart.rx_buf;
                len = read(fd,data,len>1024?1024:len);
                _uart.stats.rx_acc += len;
                _uart.stats.rx_len = len;
                _uart.stats.rx_stats = rx_done;
            }
        }
    }
    return NULL;
}

void uart_config(void)
{
    struct termios newtio;

    tcgetattr(fd,&newtio);
    // bzero(&newtio);

    cfsetispeed(&newtio,B115200);
    cfsetospeed(&newtio,B115200);

    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;
    newtio.c_cflag &= ~PARENB;
    newtio.c_cflag &= ~INPCK;
    newtio.c_cflag |= CS8;
    newtio.c_cflag &= ~CSTOPB;
    newtio.c_cflag &= ~CRTSCTS;
    newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    newtio.c_oflag &= ~OPOST;

    tcflush(fd,TCIFLUSH);

    newtio.c_cc[VTIME] = 10;
    newtio.c_cc[VMIN] = 0;

    tcsetattr(fd,TCSANOW,&newtio);

}

void uart_dispatcher(void *arg)
{
    if(_uart.rx_enabled == 0)
        return;

    if(_uart.stats.rx_stats == rx_done){
        (_uart.dispatcher_cb == NULL) ? 0 : _uart.dispatcher_cb(_uart.uart_no,_uart.dispatcher_data);
        _uart.stats.rx_stats = rx_idel;
    }
}

void uart_init(void)
{
    pthread_t thread;
    static struct cb_info ci;

    fd = open("/dev/cu.usbmodem1413",O_RDWR | O_NOCTTY | O_SYNC);
    if(fd == -1){
        perror("open");
        exit(1);
    }

    printf("open ok\n");

    uart_config();

    _uart.rx_buf = calloc(1,1024);
    _uart.tx_buf = calloc(1,1024);
    // event_add(&uart_event.h);

    // event_add_poll_cb(uart_dispatcher,NULL);
    event_add_poll_cb_ex(&ci,uart_dispatcher,NULL);

    pthread_create(&thread,NULL,uart,NULL);
}

void uart_set_dispatcher(int uartNo, void(*cb)(int uartNo, void *userdata), void *userdata)
{
    _uart.dispatcher_cb = cb;
    _uart.dispatcher_data = userdata;
}

void *uart_config_get_default(int uartNo) 
{
    (void)uartNo;

    struct uart_config *cfg = malloc(sizeof(struct uart_config));

    memcpy(cfg,&_uart.cfg,sizeof(struct uart_config));
    return cfg;
}

void uart_config_set_baud_rate(void *c, int baud)
{
    struct uart_config *cfg = c;

    cfg->baud_rate = baud;
}

void uart_config_set_rx_params(void *c, int rxSize, int rxFlowControl, int rxLingerMicros)
{

}

void uart_config_set_tx_params(void *c, int txBufSize, int txFlowControl)
{

}

int uart_configure(int uartNo, void *c)
{
    struct uart_config *cfg = c;

    (void)uartNo;

    return 1;
}

int uart_write(int uartNo, char *p, int len)
{
    return len;
}

int uart_read(int uartNo, void *p, int len)
{
    return len;
}

int uart_write_avail(int uartNo)
{
    return 1;
}

int uart_read_avail(int uartNo)
{
    return _uart.stats.rx_len;
}

void uart_set_rx_enabled(int uartNo, int en)
{
    _uart.rx_enabled = 1;
}

int uart_is_rx_enabled(int uartNo)
{
    return _uart.rx_enabled;
}

void uart_flush(int uartNo)
{

}